package com.sunlake.spring.main.model.course.service.impl;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sunlake.spring.main.common.response.R;
import com.sunlake.spring.main.model.auth.mapper.UsersMapper;
import com.sunlake.spring.main.model.auth.po.UsersPO;
import com.sunlake.spring.main.model.course.dto.CourseContentDTO;
import com.sunlake.spring.main.model.course.dto.CourseContentDTO.CourseOutlineLessonDTO;
import com.sunlake.spring.main.model.course.dto.CourseContentDTO.CoursePreviewDTO;
import com.sunlake.spring.main.model.course.dto.CourseQueryDTO;
import com.sunlake.spring.main.model.course.mapper.CourseInstructorMapper;
import com.sunlake.spring.main.model.course.mapper.CourseMapper;
import com.sunlake.spring.main.model.course.mapper.CourseReviewMapper;
import com.sunlake.spring.main.model.course.po.CourseInstructorPO;
import com.sunlake.spring.main.model.course.po.CoursePO;
import com.sunlake.spring.main.model.course.po.CourseReviewPO;
import com.sunlake.spring.main.model.course.service.CourseService;
import com.sunlake.spring.main.model.course.vo.CourseCategoryVO;
import com.sunlake.spring.main.model.course.vo.CourseDetailVO;
import com.sunlake.spring.main.model.course.vo.CourseItemVO;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 课程服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CourseServiceImpl implements CourseService {

    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.CHINA);
    private static final int DEFAULT_FEATURED_LIMIT = 6;
    private static final int NEW_COURSE_THRESHOLD_DAYS = 30;
    private static final Pattern NUMERIC_PATTERN = Pattern.compile("^\\d+$");

    private final CourseMapper courseMapper;
    private final CourseReviewMapper courseReviewMapper;
    private final CourseInstructorMapper courseInstructorMapper;
    private final UsersMapper usersMapper;
    private final ObjectMapper objectMapper;

    @Override
    public R<List<CourseItemVO>> getFeaturedCourses() {
        List<CoursePO> courseList = courseMapper.selectFeatured(DEFAULT_FEATURED_LIMIT);
        List<CourseItemVO> voList = courseList.stream()
            .map(this::buildCourseItemVO)
            .collect(Collectors.toList());
        return R.ok(200, "查询成功", voList);
    }

    @Override
    public R<PageInfo<CourseItemVO>> getCourses(CourseQueryDTO queryDTO) {
        PageHelper.startPage(queryDTO.getPage(), queryDTO.getLimit());
        List<CoursePO> courseList = courseMapper.selectByConditions(trimToNull(queryDTO.getKeyword()),
            trimToNull(queryDTO.getCategory()), trimToNull(queryDTO.getDifficulty()));
        List<CourseItemVO> voList = courseList.stream()
            .map(this::buildCourseItemVO)
            .collect(Collectors.toList());
        PageInfo<CoursePO> originPage = new PageInfo<>(courseList);
        PageInfo<CourseItemVO> targetPage = PageInfo.of(voList);
        targetPage.setTotal(originPage.getTotal());
        targetPage.setPageNum(originPage.getPageNum());
        targetPage.setPageSize(originPage.getPageSize());
        targetPage.setPages(originPage.getPages());
        return R.ok(200, "查询成功", targetPage);
    }

    @Override
    public R<CourseDetailVO> getCourseDetail(Long courseId) {
        CoursePO coursePO = courseMapper.selectById(courseId);
        if (coursePO == null) {
            return buildError(404, "课程不存在");
        }
        CourseDetailVO detailVO = buildCourseDetailVO(coursePO);
        return R.ok(200, "查询成功", detailVO);
    }

    @Override
    public R<List<CourseCategoryVO>> getCategories() {
        List<String> categories = courseMapper.selectAllCategories();
        if (categories == null || categories.isEmpty()) {
            return R.ok(200, "查询成功", Collections.emptyList());
        }
        Set<String> categorySet = new HashSet<>();
        for (String category : categories) {
            if (!hasText(category)) {
                continue;
            }
            String[] parts = category.split(",");
            for (String part : parts) {
                if (hasText(part)) {
                    categorySet.add(part.trim());
                }
            }
        }
        List<CourseCategoryVO> voList = categorySet.stream()
            .map(item -> new CourseCategoryVO(item, item, null))
            .collect(Collectors.toList());
        return R.ok(200, "查询成功", voList);
    }

    private CourseItemVO buildCourseItemVO(CoursePO coursePO) {
        CourseContentDTO courseContent = parseCourseContent(coursePO.getCourseContent());
        CourseItemVO vo = new CourseItemVO();
        vo.setId(String.valueOf(coursePO.getId()));
        vo.setTitle(coursePO.getTitle());
        vo.setDescription(coursePO.getDescription());
        vo.setCoverImage(coursePO.getCoverImage());
        vo.setInstructorName(resolveInstructorName(coursePO));
        vo.setDifficulty(coursePO.getDifficulty());
        vo.setPrice(coursePO.getPrice());
        vo.setPriceLabel(formatPrice(coursePO.getPrice()));
        vo.setHighlightTag(resolveHighlightTag(courseContent));
        vo.setIsNew(isNewCourse(coursePO.getCreatedAt()));
        vo.setCategoryIds(resolveCategories(coursePO, courseContent));
        vo.setTags(resolveTags(courseContent));
        return vo;
    }

    private CourseDetailVO buildCourseDetailVO(CoursePO coursePO) {
        CourseContentDTO courseContent = parseCourseContent(coursePO.getCourseContent());
        CourseDetailVO detailVO = new CourseDetailVO();
        detailVO.setId(String.valueOf(coursePO.getId()));
        detailVO.setTitle(coursePO.getTitle());
        detailVO.setHeadline(courseContent != null && hasText(courseContent.getHeadline())
            ? courseContent.getHeadline() : coursePO.getDescription());
        detailVO.setCoverImage(coursePO.getCoverImage());
        CourseInstructorPO instructorPO = resolveInstructor(coursePO);
        detailVO.setInstructorName(resolveInstructorName(coursePO, instructorPO));
        detailVO.setInstructorTitle(instructorPO != null ? instructorPO.getTitle() : null);
        detailVO.setInstructorAvatar(instructorPO != null ? instructorPO.getAvatar() : null);
        detailVO.setDifficulty(coursePO.getDifficulty());
        detailVO.setLessonsCount(resolveLessonsCount(coursePO, courseContent));
        detailVO.setDurationLabel(resolveDurationLabel(coursePO, courseContent));
        detailVO.setPrice(coursePO.getPrice());
        detailVO.setPriceLabel(formatPrice(coursePO.getPrice()));
        detailVO.setOriginalPriceLabel(null);
        detailVO.setDescription(coursePO.getDescription());
    detailVO.setAudience(courseContent != null ? emptySafeList(courseContent.getAudience()) : Collections.emptyList());
    detailVO.setLearningHighlights(courseContent != null ? emptySafeList(courseContent.getLearningHighlights()) : Collections.emptyList());
        detailVO.setOutline(buildOutline(courseContent));
        detailVO.setReviews(buildReviews(coursePO.getId()));
        detailVO.setPreviewMedia(buildPreview(courseContent));
        return detailVO;
    }

    private CourseContentDTO parseCourseContent(String courseContentJson) {
        if (!hasText(courseContentJson)) {
            return null;
        }
        try {
            return objectMapper.readValue(courseContentJson, CourseContentDTO.class);
        } catch (JsonProcessingException e) {
            log.warn("解析课程内容失败: {}", e.getMessage());
            return null;
        }
    }

    private String resolveInstructorName(CoursePO coursePO) {
        return resolveInstructorName(coursePO, resolveInstructor(coursePO));
    }

    private String resolveInstructorName(CoursePO coursePO, CourseInstructorPO instructorPO) {
        if (instructorPO != null) {
            return defaultIfBlank(instructorPO.getDisplayName(), instructorPO.getName());
        }
        return defaultIfBlank(coursePO.getInstructorId(), "未命名讲师");
    }

    private CourseInstructorPO resolveInstructor(CoursePO coursePO) {
        if (!hasText(coursePO.getInstructorId())) {
            return null;
        }
        CourseInstructorPO instructor = null;
        if (hasText(coursePO.getInstructorId())) {
            instructor = courseInstructorMapper.selectByDisplayName(coursePO.getInstructorId().trim());
            if (instructor == null && isNumeric(coursePO.getInstructorId())) {
                try {
                    long instructorId = Long.parseLong(coursePO.getInstructorId().trim());
                    instructor = courseInstructorMapper.selectById(instructorId);
                } catch (NumberFormatException ex) {
                    log.debug("解析讲师ID失败: {}", coursePO.getInstructorId());
                }
            }
        }
        return instructor;
    }

    private Integer resolveLessonsCount(CoursePO coursePO, CourseContentDTO courseContent) {
        if (courseContent != null && courseContent.getLessonsCount() != null) {
            return courseContent.getLessonsCount();
        }
        if (courseContent != null && courseContent.getOutline() != null) {
            return courseContent.getOutline().stream()
                .filter(Objects::nonNull)
                .mapToInt(section -> section.getLessons() == null ? 0 : section.getLessons().size())
                .sum();
        }
        return coursePO.getDuration();
    }

    private String resolveDurationLabel(CoursePO coursePO, CourseContentDTO courseContent) {
        if (courseContent != null && hasText(courseContent.getDurationLabel())) {
            return courseContent.getDurationLabel();
        }
        if (coursePO.getDuration() != null) {
            return String.format(Locale.CHINA, "约 %d 分钟", coursePO.getDuration());
        }
        return null;
    }

    private List<String> resolveCategories(CoursePO coursePO, CourseContentDTO courseContent) {
        Set<String> categories = new HashSet<>();
        if (courseContent != null && courseContent.getCategoryIds() != null) {
            categories.addAll(courseContent.getCategoryIds());
        }
        if (hasText(coursePO.getCategory())) {
            String[] parts = coursePO.getCategory().split(",");
            for (String part : parts) {
                if (hasText(part)) {
                    categories.add(part.trim());
                }
            }
        }
        return new ArrayList<>(categories);
    }

    private List<String> resolveTags(CourseContentDTO courseContent) {
        if (courseContent == null || courseContent.getTags() == null) {
            return Collections.emptyList();
        }
        return new ArrayList<>(courseContent.getTags());
    }

    private String resolveHighlightTag(CourseContentDTO courseContent) {
        if (courseContent == null || courseContent.getTags() == null || courseContent.getTags().isEmpty()) {
            return null;
        }
        return courseContent.getTags().get(0);
    }

    private Boolean isNewCourse(LocalDateTime createdAt) {
        if (createdAt == null) {
            return Boolean.FALSE;
        }
        long days = Duration.between(createdAt, LocalDateTime.now(ZoneOffset.UTC)).toDays();
        return days <= NEW_COURSE_THRESHOLD_DAYS;
    }

    private List<CourseDetailVO.CourseOutlineSectionVO> buildOutline(CourseContentDTO courseContent) {
        if (courseContent == null || courseContent.getOutline() == null) {
            return Collections.emptyList();
        }
        return courseContent.getOutline().stream()
            .filter(Objects::nonNull)
            .map(section -> {
                CourseDetailVO.CourseOutlineSectionVO vo = new CourseDetailVO.CourseOutlineSectionVO();
                vo.setId(section.getId());
                vo.setTitle(section.getTitle());
                vo.setSummary(section.getSummary());
                List<CourseOutlineLessonDTO> lessons = section.getLessons();
                if (lessons != null) {
                    vo.setLessons(lessons.stream()
                        .filter(Objects::nonNull)
                        .map(lesson -> {
                            CourseDetailVO.CourseOutlineLessonVO lessonVO = new CourseDetailVO.CourseOutlineLessonVO();
                            lessonVO.setId(lesson.getId());
                            lessonVO.setTitle(lesson.getTitle());
                            lessonVO.setDuration(lesson.getDuration());
                            lessonVO.setMediaUrl(lesson.getMediaUrl());
                            return lessonVO;
                        })
                        .collect(Collectors.toList()));
                } else {
                    vo.setLessons(Collections.emptyList());
                }
                return vo;
            })
            .collect(Collectors.toList());
    }

    private List<CourseDetailVO.CourseReviewVO> buildReviews(Long courseId) {
        List<CourseReviewPO> reviewList = courseReviewMapper.selectByCourseId(courseId);
        if (reviewList == null || reviewList.isEmpty()) {
            return Collections.emptyList();
        }
        return reviewList.stream()
            .map(review -> {
                CourseDetailVO.CourseReviewVO vo = new CourseDetailVO.CourseReviewVO();
                vo.setId(String.valueOf(review.getId()));
                vo.setReviewer(resolveReviewerName(review.getUserId()));
                vo.setRating(review.getRating());
                vo.setHighlight(null);
                vo.setContent(review.getComment());
                vo.setCreatedAt(review.getCreatedAt() != null ? DATE_FORMATTER.format(review.getCreatedAt()) : null);
                return vo;
            })
            .collect(Collectors.toList());
    }

    private String resolveReviewerName(Long userId) {
        if (userId == null) {
            return "匿名用户";
        }
        UsersPO user = usersMapper.selectByPrimaryKey(userId);
        if (user == null) {
            return "用户" + userId;
        }
        if (hasText(user.getUsername())) {
            return user.getUsername();
        }
        if (hasText(user.getEmail())) {
            return user.getEmail();
        }
        return "用户" + userId;
    }

    private CourseDetailVO.CoursePreviewVO buildPreview(CourseContentDTO courseContent) {
        if (courseContent == null || courseContent.getPreviewMedia() == null) {
            return null;
        }
        CoursePreviewDTO preview = courseContent.getPreviewMedia();
        CourseDetailVO.CoursePreviewVO previewVO = new CourseDetailVO.CoursePreviewVO();
        previewVO.setType(preview.getType());
        previewVO.setUrl(preview.getUrl());
        previewVO.setDuration(preview.getDuration());
        return previewVO;
    }

    private List<String> emptySafeList(List<String> source) {
        if (source == null) {
            return Collections.emptyList();
        }
        return new ArrayList<>(source);
    }

    private String formatPrice(BigDecimal price) {
        if (price == null) {
            return "免费";
        }
        return "¥" + price.stripTrailingZeros().toPlainString();
    }

    private String trimToNull(String value) {
        return hasText(value) ? value.trim() : null;
    }

    private boolean hasText(String value) {
        return value != null && !value.trim().isEmpty();
    }

    private String defaultIfBlank(String value, String defaultValue) {
        return hasText(value) ? value : defaultValue;
    }

    private boolean isNumeric(String value) {
        if (!hasText(value)) {
            return false;
        }
        return NUMERIC_PATTERN.matcher(value.trim()).matches();
    }

    @SuppressWarnings("unchecked")
    private <T> R<T> buildError(int code, String message) {
        return (R<T>) R.error(code, message);
    }
}
